﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Zj.HttpCodeDemo.Domain.Events;

namespace Zj.HttpCodeDemo.Bus.Simple
{
    public class SimpleEventBus
        : IEventBus
    {
        private readonly MessageQueue _queue;
        private readonly IEnumerable<IEventHandler> _eventHandlers;
        private readonly IEventExcutionContext _eventExcutionContext;

        public SimpleEventBus(IEventExcutionContext eventExcutionContext)
        {
            this._queue = new MessageQueue();
            this._eventHandlers = new List<IEventHandler>();
            this._eventExcutionContext = eventExcutionContext;
        }
        public async Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default(CancellationToken)) where TEvent : IEvent
        {
            await Task.Run(() =>
            {
                _queue.Push(@event);
            });
        }

        public void Pulish<TEvent>(TEvent @event) where TEvent : IEvent
        {
            _queue.Push(@event);
        }


        public void Subscribe<TEvent, TEventHandler>()
            where TEvent : IEvent
            where TEventHandler : IEventHandler
        {
            if (!this._eventExcutionContext.HandlerRegistered(typeof(TEvent), typeof(TEventHandler)))
            {
                this._eventExcutionContext.Registe(typeof(TEvent), typeof(TEventHandler));
            }
            //_queue.eventPushed += MessageQueue_EventPushed;
        }
        private void MessageQueue_EventPushed(object sender, EventProcessedArgs e)
        {
            this._eventHandlers.Where(handler => handler.CanHandle(e.Event))
                .ToList()
                .ForEach(handler =>
                {
                    Task.Run(() =>
                    {
                        handler.HandleAsync(e.Event);
                    });
                });

        }


        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)。
                    this._queue.eventPushed -= MessageQueue_EventPushed;
                }
                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。

                disposedValue = true;
            }
        }

        // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        // ~SimpleEventBus() {
        //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
        //   Dispose(false);
        // }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器，则取消注释以下行。
            // GC.SuppressFinalize(this);
        }

        #endregion
    }
}
